Skip to content

notification-service: accept epoch timestamps and drop poison SQS messages - #1544

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1788972863-notification-consumer-timestamp
Open

devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1788972863-notification-consumer-timestamp

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix for incident Notification SQS consumer failing to process messages (NotificationConsumerProcessingErrors).

Root cause (services/notification-service/.../consumer/SqsConsumer.kt): parseMessage swapped in a strict Json { isLenient = false } parser whenever the Redis flag chaos:notification-service:consumer_strict_schema existed. SqsNotificationMessage.timestamp is typed String, so legacy events carrying an epoch number ("timestamp": 1704067200) only decoded because the lenient parser coerces unquoted literals to strings; the strict parser threw SerializationException. Failed messages were logged and counted but never deleted, so they re-entered the queue after the 60s visibility timeout and depth grew without bound.

Changes

  • SqsNotificationMessage.timestamp is now decoded via EventTimestampSerializer, which accepts an RFC 3339 string or an epoch number (seconds or millis, split at 1e11) and normalises to an ISO-8601 UTC string. Works with any parser configuration.
  • Removed the strict-parser toggle and the chaos:notification-service:consumer_strict_schema lookup from the consumer, along with the now-unused jedis dependency.
  • Poison handling in startPolling:
    event == null  -> counter++, warn, deleteMessage(...)   // redelivery cannot fix a deserialisation failure
    processEvent throws -> counter++, log (message stays for redelivery / DLQ redrive)
    
    Previously processEvent exceptions were not counted in notifications.processing.errors.
  • Tests: epoch seconds / millis / SNS-wrapped epoch decode, epoch decodes under a strict parser, and a runTest polling test asserting the unparseable message is deleted while the valid one is processed.
  • Filled in investigation/resolution steps in docs/runbooks/notification-processing-failure.md.

Note for reviewers (golden-app policy): this removes the code path behind the notification-schema scenario in scripts/bug-catalog.yaml / the admin-dashboard chaos button. Setting the flag becomes a no-op. If the lab must be preserved on main, keep this PR as the reference remediation on a workshop-* branch instead of merging.

Verified: ./gradlew build in services/notification-service (38 tests, 0 failures). No live environment was available locally, so the diagnosis is from code/runbook rather than pod logs.

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/834333f5757741e58a460024e6844856
Open in Devin Desktop: https://partner-workshops.devinenterprise.com/desktop/session/834333f5757741e58a460024e6844856?variant=devin


Devin Review

…sages

The consumer could switch to a strict JSON parser (Redis chaos flag) that
rejected legacy events carrying epoch-int timestamps; unparseable messages
were never deleted, so they cycled through the visibility timeout and the
queue grew without bound.

- Decode SqsNotificationMessage.timestamp via EventTimestampSerializer,
  accepting RFC 3339 strings or epoch seconds/millis regardless of parser
  strictness.
- Remove the strict-parser toggle and the jedis dependency it needed.
- Delete messages that fail deserialization (redelivery can't fix them) and
  count processEvent exceptions in notifications.processing.errors.
- Fill in the runbook investigation/resolution steps.
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Devin Review

Comment on lines 94 to +96
return try {
// Try parsing as direct message first
parser.decodeFromString<SqsNotificationMessage>(body)
json.decodeFromString<SqsNotificationMessage>(body)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Notification failure demo becomes inert

Every notification-schema injection now leaves parseMessage lenient because it never reads the Redis flag. The scenario catalog still offers this planted failure, so demos report success without breaking notification processing.

Prompt for agents
Restore the notification-schema planted failure while retaining normal support for epoch timestamps. SqsConsumer.parseMessage must consult chaos:notification-service:consumer_strict_schema and reject legacy numeric timestamps only when that scenario is active. Keep normal production parsing compatible with epoch seconds and milliseconds. Preserve scripts/bug-catalog.yaml, inject-bug.sh, the admin dashboard button, and the alert-driven demo contract. If this remediation belongs only on a workshop variant rather than main, move the change to that branch instead of changing the golden app.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional and called out in the PR description: the strict-parser toggle is the root cause of the incident this PR remediates, so the remediation necessarily makes the notification-schema scenario inert. Whether that belongs on main (golden-app policy) or only on a workshop-* variant branch is a call for the maintainers — I've asked in the session. If the answer is "keep the lab", I'll retarget this PR at a workshop branch rather than re-adding a flag-gated failure path to production code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants